package com.zhenghaijin.recommendationservice.service.impl;

import com.zhenghaijin.recommendationservice.mapper.UserBehaviorMapper;
import com.zhenghaijin.recommendationservice.mapper.UserRecommendationMapper;
import com.zhenghaijin.recommendationservice.model.UserBehavior;
import com.zhenghaijin.recommendationservice.model.UserRecommendation;
import com.zhenghaijin.recommendationservice.service.RecommendationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.scheduling.annotation.Async;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Service
public class RecommendationServiceImpl implements RecommendationService {

    private static final Logger logger = LoggerFactory.getLogger(RecommendationServiceImpl.class);

    @Autowired
    private UserBehaviorMapper behaviorMapper;

    @Autowired
    private UserRecommendationMapper recommendationMapper;

    private Map<Long, List<Long>> localCache = new ConcurrentHashMap<>();

    @Override
    public void saveUserBehavior(UserBehavior behavior) {
        logger.info("Saving user behavior: {}", behavior);
        behavior.setBehaviorTime(LocalDateTime.now());
        behaviorMapper.insert(behavior);
    }

    @Override
    @Cacheable("recommendations")
    public List<Long> getRecommendations(Long userId) {
        logger.info("Fetching recommendations for user: {}", userId);
        return localCache.getOrDefault(userId, Collections.emptyList());
    }

    @Override
    @Cacheable("recommendations")
    public Page<Long> getRecommendations(Long userId, Pageable pageable) {
        logger.info("Fetching paginated recommendations for user: {}", userId);
        List<Long> recommendations = localCache.getOrDefault(userId, Collections.emptyList());
        int start = (int) pageable.getOffset();
        int end = Math.min((start + pageable.getPageSize()), recommendations.size());
        return new PageImpl<>(recommendations.subList(start, end), pageable, recommendations.size());
    }

    @Override
    @Async
    public void refreshRecommendations() {
        logger.info("Refreshing all recommendations asynchronously");
        List<Long> userIds = behaviorMapper.getAllUserIds();
        for (Long userId : userIds) {
            List<Long> animeIds = behaviorMapper.getAnimeIdsByUser(userId);
            Map<Long, Long> frequency = animeIds.stream()
                    .collect(Collectors.groupingBy(id -> id, Collectors.counting()));
            List<Long> sorted = frequency.entrySet().stream()
                    .sorted(Map.Entry.<Long, Long>comparingByValue().reversed())
                    .map(Map.Entry::getKey)
                    .limit(10)
                    .collect(Collectors.toList());
            localCache.put(userId, sorted);
            UserRecommendation rec = new UserRecommendation();
            rec.setUserId(userId);
            rec.setRecommendedAnimeIds(sorted.stream()
                    .map(String::valueOf).collect(Collectors.joining(",")));
            rec.setUpdateTime(LocalDateTime.now());
            recommendationMapper.upsert(rec);
        }
    }
}